/*
 * Copyright (c) 2011 Jean-Marc Perronne
 * Ensisa, 12 rue des Freres Lumieres, F-68093 Mulhouse cedex
 * All rights reserved.
 *
 * The copyright of this software is owned by Werner Randelshofer. 
 * You may not use, copy or modify this software, except in  
 * accordance with the license agreement you entered into with  
 * Jean-Marc Perronne. For details see accompanying license terms. 
 */

package fr.uha.ensisa.jmp.drone.ui.instrument;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import fr.uha.ensisa.jmp.drone.ui.instrument.dial.CompoundDial;
import fr.uha.ensisa.jmp.drone.ui.instrument.dial.renderer.DefaultCompoundDialRenderer;


public class HorizonRenderer extends DefaultCompoundDialRenderer
{
	private static final Color SKY_COLOR = new Color(0, 204, 255);
	private static final Color GROUND_COLOR = new Color(153, 102, 51);
	private static final Color GRADUATION_COLOR = Color.WHITE;

	private static final double MajorGradutionRatio = 0.25;
	private static final int LabelSpace = 2;
	private static final int BorderSize = 10;

	private static final double MinorGradutionRatio = MajorGradutionRatio * 1.5;
	private static final Stroke MinorGradutionStroke = new BasicStroke(0.5f);
	private static final Stroke MajorGradutionStroke = new BasicStroke(2f);

	private final String planePicturePath;

	private BufferedImage HorizonImage;
	private BufferedImage planeImage;
	private AffineTransform horizonTransform;
	private AffineTransform planeTransform;
	private Ellipse2D clip;
	private RenderingHints rh; 
	private Dimension cadranSize;

	public HorizonRenderer(CompoundDial dial, String planePicturePath)
	{
		super(dial);
		this.horizonTransform = new AffineTransform();
		this.planeTransform = new AffineTransform();
		this.planePicturePath = planePicturePath;
		Dimension size = this.getSize();
		this.cadranSize = new Dimension((int) size.getWidth()-BorderSize, (int) size.getHeight()-BorderSize);
		this.setupPictures();
	}

	private void centerPlanePicture()
	{
		Dimension sz = this.getSize();
		double tx = (sz.getWidth()-planeImage.getWidth())/2;
		double ty = (sz.getHeight()-planeImage.getHeight())/2;
		this.planeTransform.setToTranslation(tx,ty);
	}
	
	private void setupClip()
	{
		Dimension d = this.cadranSize;
		this.clip = new Ellipse2D.Double(BorderSize/2, BorderSize/2, d.getWidth(), d.getHeight());
	}
	
	private void setupPictures()
	{
		try
		{
			this.renderBackground(null);
			this.planeImage = ImageIO.read(new File(this.planePicturePath));
			this.centerPlanePicture();
			this.setupClip();
			this.rh = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
			this.rh.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 

		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}	
	
	@Override
	public void renderBackground(Graphics2D g)
	{
		Dimension size = this.cadranSize;
		this.HorizonImage = new BufferedImage((int) size.getWidth(), (int) size.getHeight() * 3, BufferedImage.TYPE_INT_RGB);
		Graphics2D g2 = this.HorizonImage.createGraphics();

		// drawing sky
		g2.setColor(SKY_COLOR);
		g2.fillRect(0, 0, this.HorizonImage.getWidth(), this.HorizonImage.getHeight() / 2);
		// drawing ground
		g2.setColor(GROUND_COLOR);
		g2.fillRect(0, this.HorizonImage.getHeight() / 2, this.HorizonImage.getWidth(), this.HorizonImage.getHeight() /2);
		
		this.renderTicks(g2);

		g2.dispose();
	}
	
	public void renderTicks(Graphics2D g2)
	{
		g2.setColor(GRADUATION_COLOR);
		final int max = this.dial.getModel().getMaximum("pitch");
		final int min = this.dial.getModel().getMinimum("pitch");
		final int majorTickSpacing = this.dial.getModel().getMajorTickSpacing("pitch");
		final int minorTickSpacing = this.dial.getModel().getMinorTickSpacing("pitch");
		final int majorLineXStart = (int) (this.HorizonImage.getWidth() * MajorGradutionRatio);
		final int majorLineXEnd = this.HorizonImage.getWidth() - majorLineXStart;
		final int minorLineXStart = (int) (this.HorizonImage.getWidth() * MinorGradutionRatio);
		final int minorLineXEnd = this.HorizonImage.getWidth() - minorLineXStart;
		
		int nbValues = (max-min)/minorTickSpacing;
		double graduationsInterval = ((double) this.HorizonImage.getHeight()) / nbValues;

		for (int i = 0; i < nbValues; i++)
		{
			g2.setStroke(MinorGradutionStroke);
			g2.drawLine(minorLineXStart, (int) (i * graduationsInterval), minorLineXEnd, (int) (i * graduationsInterval));
		}

		nbValues = (max-min)/majorTickSpacing;
		graduationsInterval = ((double) this.HorizonImage.getHeight()) / nbValues;

		for (int i = 0, value = max; i < nbValues; i++, value-=majorTickSpacing)
		{
			g2.setStroke(MajorGradutionStroke);
			g2.drawLine(majorLineXStart, (int) (i * graduationsInterval), majorLineXEnd, (int) (i * graduationsInterval));
			
			final String vString = String.valueOf(value);
			final int strWidth = g2.getFontMetrics().stringWidth(vString);
			g2.drawString(vString, majorLineXStart - strWidth - LabelSpace, (int) (i * graduationsInterval));
			g2.drawString(vString, majorLineXEnd + LabelSpace, (int) (i * graduationsInterval));

		}
	}
	
	@Override
	public void renderDial(Graphics2D g)
	{
		if (this.HorizonImage == null || this.planeImage==null) return;

		final int max = this.dial.getModel().getMaximum("pitch");
		final int min = this.dial.getModel().getMinimum("pitch");
		final int value = this.dial.getModel().getValue("pitch");

		int deltaPitchTranslation = value*this.HorizonImage.getHeight()/(max-min);
		int pitchTranslation = this.HorizonImage.getHeight() /3;

		this.horizonTransform.setToIdentity();
		
		this.horizonTransform.translate(BorderSize/2, BorderSize/2);

		this.horizonTransform.translate(this.HorizonImage.getWidth()/2, (pitchTranslation )/2);
		this.horizonTransform.rotate(Math.toRadians(this.dial.getModel().getValue("roll")));
		this.horizonTransform.translate(-this.HorizonImage.getWidth()/2, -(pitchTranslation)/2);

		this.horizonTransform.translate(0, -pitchTranslation + deltaPitchTranslation);
	
		g.setRenderingHints(this.rh);	
		
		Dimension d = this.getSize();
		//g.setPaint(new GradientPaint(d.width/2, d.height/2, Color.gray,d.width, d.height, Color.black));
		g.setColor(Color.DARK_GRAY);
		g.fillOval(0,0,(int)d.getWidth(), (int)d.getHeight());
		//g.setColor(Color.DARK_GRAY);
		//g.drawOval(0,0,(int)d.getWidth(), (int)d.getHeight());

		g.clip(this.clip);
		g.drawImage(this.HorizonImage, this.horizonTransform, null);
		g.drawImage(this.planeImage, this.planeTransform, null);
			
	}

	
	@Override
	public void setSize(Dimension size)
	{
		super.setSize(size);
		this.cadranSize = new Dimension((int) size.getWidth()-BorderSize, (int) size.getHeight()-BorderSize);
		this.setupPictures();
		this.dial.repaint();
	}

}
